package uebung11;

import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

public class InteractiveChart extends BarChart implements TemperatureClient,
		InteractiveChartTestInterface {

	/**
	 * Stores a list with up to 30 measurements for each location. This list is
	 * used to compute the average temperature for this location.
	 */
	// private HashMap<Long, Measurement> tempHistoryPerLocation = new
	// HashMap<Long, Measurement>();
	private HashMap<Integer, Measurement> tempHistoryPerLocation = new HashMap<Integer, Measurement>();

	// ID for all Measurements
	int countTotalMeasurements;

	/**
	 * Alphabetically sorted list of all locations. This variable is needed, as
	 * the keys in the tempHistoryPerLocation map are not ordered. Whenever a
	 * measurement from a new location is received this list needs to be
	 * re-sorted.
	 */
	private LinkedList<String> allLocations = new LinkedList<String>();

	/**
	 * Stored for testing purposes
	 */
	private Map lastDiagramData = new HashMap<String, Double>();

	/**
	 * Record for storing measurements from temperature sensors
	 */
	class Measurement {
		Measurement(long t, String l, double temp) {
			time = t;
			location = l;
			temperature = temp;
		}

		public long time;
		public String location;
		public double temperature;
	}

	/**
	 * returns the locations of the last diagram
	 * 
	 * @return the locations used for the last displayed diagram
	 */
	public LinkedList getLastDiagramLocations() {
		return allLocations;
	}

	/**
	 * returns the data used for the last diagram
	 * 
	 * @return the data used for the last displayed diagram
	 */
	public Map getLastDiagramData() {
		return lastDiagramData;
	}

	/**
	 * Called whenever a new temperature is measured by a sensor.
	 * 
	 * @param timestamp
	 *            The time when the measurement was taken, given in microseconds
	 *            since 1.1.1970
	 * @param location
	 *            The location where the measurement was taken
	 * @param temperature
	 *            The measured temperature
	 */
	public void newTemperature(long timestamp, String location,
			double temperature) {
		// Neue "locations" sollen in die Liste aufgenommen werden,
		// die fuer sie gemessenen Werte sind entsprechend passend
		// zu speichern (Tipp: sehen Sie sich die Attribute dieser Klasse an).
		// Zusaetzlich sollen die Orte alphabetisch geordnett und diese Ordnung
		// "geeignete Art und Weise" beim Zeichnen beruecksichtigt werden
		// (die daten von Raum "A" kommen als Balken vor denen von Raum "B").
		// Neben bzw. anstelle der zuletzt fuer den jeweiligen ort gemessenen
		// Temperatur soll auch der Durchschnitt angezeigt fuer diesen Ort
		// berechnet werden, begrenzt auf den Durchschnitt der letzten 30
		// Messwerte.
		// Hinweis: bearbeiten Sie die Aufgabe schrittweise und testen Sie
		// zwischendrin immer wieder, ob die Ausgabe plausibel ist.

		println(location + ": " + temperature);

		putNewLocation(location);
		putHistoryPerLocation(new Measurement(timestamp, location, temperature));
		lastDiagramData = getDiagramData();

		// displayDiagram ...
		setOrder(allLocations);
		displayDiagram(lastDiagramData, 30L);
	}

	/**
	 * Inserts a location in allLocations in alphabetical order if it does not
	 * already exist.
	 * 
	 * @param location
	 *            Name of the new Location, that has to be inserted.
	 */
	private void putNewLocation(String location) {
		boolean placed = false;
		int i = 0;
		while (!placed) {
			if (allLocations.contains(location))
				placed = true;
			else if (i >= allLocations.size()) {
				allLocations.add(location);
				placed = true;
			} else if (allLocations.get(i).compareTo(location) > 0) {
				allLocations.add(i, location);
				placed = true;
			} else
				i++;
		}
	}

	/**
	 * Updates the tempHistoryPerLocation Variable with new Measurement. Removes
	 * the oldest occurrence if number if Measurements for one location exceeds
	 * 30.
	 * 
	 * @param newMeasurement
	 *            measurement data to be placed in History.
	 */
	private void putHistoryPerLocation(Measurement newMeasurement) {
		int count = 0;
		int firstOccurance = -1;

		// count how often current location occurs in history,
		// remove first occurrence if count is 30.
		for (Integer i : tempHistoryPerLocation.keySet()) {

			if (tempHistoryPerLocation.get(i).location == newMeasurement.location) {
				if (firstOccurance == -1)
					firstOccurance = i;
				count++;
			}
		}

		// remove first elmt if limit is exceeded.
		if (count == 30)
			// println(tempHistoryPerLocation.containsKey(firstOccurance));
			tempHistoryPerLocation.remove(firstOccurance);

		tempHistoryPerLocation.put(countTotalMeasurements, newMeasurement);
		countTotalMeasurements++;
	}

	/**
	 * Calculates the data for Diagram from tempHistoryPerLocation variable. It
	 * counts the measurements per location and stores its average.
	 * 
	 * @return average temperatures per location to build diagram BarChart.
	 */
	public Map<String, Double> getDiagramData() {
		Map<String, Double> returnData = new HashMap<String, Double>(
				allLocations.size());
		for (String loc : allLocations) {
			double tempSum = 0L;
			int count = 0;
			for (Measurement m : (Measurement[]) tempHistoryPerLocation
					.values().toArray(new Measurement[0])) {
				if (m.location == loc) {
					count++;
					tempSum += m.temperature;
				}
			}
			System.out.println("Temp Count Temp/Count " + tempSum + " " + count
					+ " " + tempSum / count);
			returnData.put(loc, tempSum / count);
		}
		return returnData;
	}

	/**
	 * Open a new window and start the TemperatureTicker. Do not change this
	 * method!
	 * 
	 * @param args
	 *            command line parameters are not used in this exercise
	 */
	public static void main(String[] args) {
		InteractiveChart chart = new InteractiveChart();
		chart.start();

		// start the temperature ticker
		TemperatureTicker.initSensor(chart);
	}
}
